import Overlay from './Overlay'
export default class GltfModel extends Overlay {
  constructor ({
    sandbox,
    url,
    position = { x: 0, y: 0, z: 0 },
    rotation = { x: 0, y: 0, z: 0 },
    scale = 1,
    enableCache = true,
    isCastShadow,
    isReceiveShadow,
    isChangeMatMetal = false,
    isDoubleSide = false,
    isAddScene = true,
    roughness = 0.3,
    metalness = 0.7,
    enableClearCoatMat = false
  }) {
    super()
    this.sandbox = sandbox
    this.scene = sandbox.scene
    this.url = url
    this.model = null
    this._position = position
    this._rotation = rotation
    this._scale = scale
    this.enableCache = enableCache
    this.isCastShadow = isCastShadow
    this.isReceiveShadow = isReceiveShadow
    this.isChangeMatMetal = isChangeMatMetal
    this.isDoubleSide = isDoubleSide
    this.isAddScene = isAddScene
    this.roughness = roughness
    this.metalness = metalness
    this.enableClearCoatMat = enableClearCoatMat
    this.loader = window.sandbox.gltfLoader
    return this.initOverlay()
  }

  async initOverlay () {
    // this.model = await this.loader.loadAsync(this.url)
    this.model = await this.loader.loadResource(this.url, this.enableCache)
    this.overlay = this.model.scene
    this.setMarerial()
    const { x, y, z } = this._position
    this.overlay.position.set(x, y, z)
    this.overlay.rotation.set(
      GC.MathUtils.degToRad(this._rotation.x), // 将度转换为弧度
      GC.MathUtils.degToRad(this._rotation.y),
      GC.MathUtils.degToRad(this._rotation.z)
    )
    const scaleArr = Array.isArray(this._scale) ? this._scale : [this._scale, this._scale, this._scale]
    this.overlay.scale.set(...scaleArr)

    if (this.isAddScene) {
      this.scene.add(this.overlay)
    }

    this.animations = this.model.animations
    this.mixer = new GC.AnimationMixer(this.overlay)
    this.mixer.addEventListener('finished', () => {
      console.log('结束')
      this._animationPlaying = false
    })
    // 在 initOverlay 里（this.overlay 已存在）
    this.overlay.setMarerialOpacity = (opacityValue, color) => {
      this.setMarerialOpacity(opacityValue, color) // 直接复用类里已写好的逻辑
    }
    this.overlay.ResetMaterial = () => {
      this.ResetMaterial()
    }
    this.overlay.changeMaterialColor = () => {
      this.changeMaterialColor()
    }
    this.changeMaterialColor()
    return this
  }

  setMarerialOpacity (opacityValue = 0.1, color = '#2e547b') {
    const hexColor = new GC.Color(color)
    this.overlay.traverse(child => {
      if (child.isMesh) {
        if (!child.OriMaterial) {
          child.OriMaterial = child.material.clone()
        }
        child.material = new GC.MeshStandardMaterial({
          map: child.material.map,
          transparent: true,
          opacity: opacityValue,
          alphaTest: 0.1,
          color: hexColor
          // color: child.material.color
        })
        // child.material.transparent=true
        // child.material.opacity=0.1
        // child.material.alphaTest=0.1
        child.material.needsUpdate = true
      }
    })
  }

  // 恢复默认材质
  ResetMaterial () {
    this.overlay.traverse(child => {
      if (child.isMesh) {
        if (child.OriMaterial) {
          child.material = child.OriMaterial
          child.material.needsUpdate = true
        }
      }
    })
  }

  setMarerial () {
    if (this.enableClearCoatMat) {
      window.sandbox.logger.log('设置清漆', this.modelName)
    }
    this.overlay.traverse(child => {
      if (child.isObject3D) {
        child.castShadow = this.isCastShadow
        child.receiveShadow = this.isReceiveShadow
      }
      if (child.isMesh) {
        // 将材质的 side 属性设置为 GC.DoubleSide
        if (this.isDoubleSide) {
          child.material.side = GC.DoubleSide
        }
        if (this.isDoubleSide) {
          // 如果材质是多材质数组，也需要遍历设置
          if (Array.isArray(child.material)) {
            child.material.forEach(material => {
              material.side = GC.DoubleSide
            })
          }
        }
        if (this.enableClearCoatMat) {
          // window.sandbox.logger.log('设置清漆')
          if (Array.isArray(child.material)) {
            child.material.forEach(material => {
              material = this.getClearCoatMat(child.material.color)
            })
          } else {
            child.material = this.getClearCoatMat(child.material.color)
          }
        } else if (this.isChangeMatMetal) {
          if (Array.isArray(child.material)) {
            child.material.forEach(material => {
              material.roughness = this.roughness
              material.metalness = this.metalness
            })
          } else {
            child.material.roughness = this.roughness
            child.material.metalness = this.metalness
          }
        }
        child.material.needsUpdate = true
      }
    })
  }

  getClearCoatMat (OriColor, matName = '') {
    const physicalMaterial = new GC.MeshPhysicalMaterial({
      color: OriColor,
      roughness: 0.3,
      metalness: 0.7,
      clearcoat: 0.5, // 清漆效果
      clearcoatRoughness: 0.1,
      ior: 1
    })
    physicalMaterial.name = matName

    // const physicalMaterial = new GC.MeshStandardMaterial({
    //   color: OriColor,
    //   roughness: 0.3,
    //   metalness: 0.7
    // })
    physicalMaterial.name = matName
    return physicalMaterial
  }

  ralToHex (ral) {
    return this.RAL_MAP[ral] ?? '#000000' // 找不到返回黑色
  }

  changeMaterialColor () {
    this.RAL_MAP = {
      'RAL 5015': {
        replaceColor: '#004dfe',
        materialNames: ['#0000ffff', '#0080ffff', '#0099ffff', '#1e2d6eff']
      },
      'RAL 1021': {
        replaceColor: '#e25303',
        materialNames: ['#ff8000ff', '#e77108ff']
      },
      'RAL 1016': {
        replaceColor: '#FFEB00',
        materialNames: ['#ffff00ff']
      },
      'RAL 2002': {
        replaceColor: '#C1121C',
        materialNames: ['#C1121d']
      },
      'RAL 2004': {
        replaceColor: '#E6000A',
        materialNames: ['#E60000']
      }
    }
    this.NAME_TO_RAL = {}
    Object.entries(this.RAL_MAP).forEach(([ral, rule]) => {
      rule.materialNames.forEach(n => this.NAME_TO_RAL[n] = ral)
    })

    // console.log(this.NAME_TO_RAL)
    this.overlay.traverse(child => {
      if (!child.isMesh) return
      // console.log(child.material, this.colorToHex(child.material.color))
      // console.log(child.material.roughness, child.material.metalness, child.material.clearcoat,
      //   child.material.clearcoatRoughness, child.material.ior)
      const mats = Array.isArray(child.material) ? child.material : [child.material]
      mats.forEach(mat => {
        // 逐条规则匹配（支持包含）
        for (const [name, ral] of Object.entries(this.NAME_TO_RAL)) {
          if (mat.name.includes(name)) {
            // const hexColor = new GC.Color(this.RAL_MAP[ral].replaceColor);
            // const hexColor = new GC.Color('#0078B4');//#003074
            const replaceColor = this.RAL_MAP[ral].replaceColor
            const colorRgb = this.hexToRgb01(replaceColor)
            const hexColor = new GC.Color(colorRgb.r, colorRgb.g, colorRgb.b)// #003074
            // mat.color.copy(hexColor);
            // mat.needsUpdate = true;
            child.material = this.getClearCoatMat(hexColor, 'replace_' + replaceColor)
            child.material.needsUpdate = true
            break // 命中即停，避免重复赋值
          }
        }
      })
    })
  }

  hexToRgb01 (hex) {
    hex = hex.replace(/^#/, '') // 去掉 #
    if (hex.length !== 6) throw new Error('Invalid HEX')

    const r = parseInt(hex.slice(0, 2), 16) / 255
    const g = parseInt(hex.slice(2, 4), 16) / 255
    const b = parseInt(hex.slice(4, 6), 16) / 255

    return { r, g, b }
  }

  colorToHex (colorObj) {
    // colorObj 可以是 THREE.Color 或 GC.Color
    const r = Math.round(colorObj.r * 255)
      .toString(16)
      .padStart(2, '0')
    const g = Math.round(colorObj.g * 255)
      .toString(16)
      .padStart(2, '0')
    const b = Math.round(colorObj.b * 255)
      .toString(16)
      .padStart(2, '0')
    return `#${r}${g}${b}`.toUpperCase()
  }

  // const clock = new GC.Clock()
  get animationPlaying () {
    return this._animationPlaying || false
  }

  enableAnimation (params = { name: '', speed: 1, loop: true }) {
    this.stopAnimation()
    this._animationPlaying = true
    const { name = '', speed = 1, loop = true } = params
    this.mixer.timeScale = speed // 设置播放倍率
    const clock = new GC.Clock()
    this.animations.forEach((clip) => {
      if (!name || clip.name === name) {
        const action = this.mixer.clipAction(clip)
        action.loop = loop ? GC.LoopRepeat : GC.LoopOnce
        // action.clampWhenFinished = true
        action.play()
        action.paused = false
      }
    })
    this.updateIndex = this.sandbox.renderCalls.push(() => {
      if (this.mixer) {
        this.mixer.update(clock.getDelta())
      }
    })
  }

  stopAnimation () {
    this._animationPlaying = false
    if (this.mixer) {
      this.mixer.stopAllAction()
    }
    const index = this.sandbox.renderCalls.indexOf(this.updateIndex)
    if (index > -1) {
      this.sandbox.renderCalls.splice(index, 1) // 从找到的索引位置移除1个元素
    }
  }

  zoomTo () {
    const box = new GC.Box3().setFromObject(this.overlay)
    const size = box.getSize(new GC.Vector3())
    const center = box.getCenter(new GC.Vector3())

    // 设置相机位置和朝向
    const maxSize = Math.max(size.x, size.y, size.z)
    const cameraDistance = maxSize * 2.0
    this.sandbox.camera.position.set(
      center.x + cameraDistance,
      center.y + cameraDistance / 2,
      center.z + cameraDistance / 2
    )
    this.sandbox.camera.lookAt(center.x, center.y, center.z)
  }

  get modelName () {
    const filePath = this.url
    const lastSlashIndex = filePath.lastIndexOf('/')
    const fileNameWithExt = filePath.substring(lastSlashIndex + 1)

    const lastDotIndex = fileNameWithExt.lastIndexOf('.')
    return fileNameWithExt.substring(0, lastDotIndex)
  }
}
